// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

#pragma once

using namespace System;

#define MAXIMUM_NUMBER_TRACKS	100
#define IOCTL_CDROM_RAW_READ	0x2403E
#define IOCTL_CDROM_READ_TOC	0x24000
#define CD_BLOCKS_PER_SECOND	75
#define RAW_SECTOR_SIZE			2352
#define CD_SECTOR_SIZE			2048
#define SECTORS_AT_READ			20
#define MAX_READ_BUFFER_SIZE	RAW_SECTOR_SIZE*SECTORS_AT_READ

typedef struct _TRACK_DATA
{
	UCHAR Reserved;
	UCHAR Control : 4;
	UCHAR Adr : 4;
	UCHAR TrackNumber;
	UCHAR Reserved1;
	UCHAR Address[4];
} TRACK_DATA;

typedef struct _CDROM_TOC
{
	UCHAR Length[2];
	UCHAR FirstTrack;
	UCHAR LastTrack;
	TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
} CDROM_TOC;

typedef enum _TRACK_MODE_TYPE
{
	YellowMode2,
	XAForm2,
	CDDA
} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;

typedef struct __RAW_READ_INFO
{
	LARGE_INTEGER  DiskOffset;
	ULONG  SectorCount;
	TRACK_MODE_TYPE  TrackMode;
} RAW_READ_INFO, *PRAW_READ_INFO;

namespace core2namespace {

// ....................................................................................................................
// Trieda ITackItem
// ....................................................................................................................
public ref class ITrackItem {
public:
	String^ TrackName;
	unsigned __int64 TrackAddress;
	unsigned __int64 TrackLength;
	int TrackLengthInTime;
	unsigned int TrackType;
	unsigned char TOC_Address_1, TOC_Address_2, TOC_Address_3, TOC_Address_4;

//	String^ Artist;
//	String^ Title;
//	String^ Year;
//	String^ Genre;
public:
	// Konstruktor
	ITrackItem() {
		TrackName = "";
		TrackAddress = 0; TrackLength = 0;
		TrackLengthInTime = 0; TrackType = 0;
	}
	// Konstruktor
	ITrackItem(ITrackItem ^pValue) {
		Assign(pValue);
	}
	// Skopirovanie obsahu
	void Assign(ITrackItem ^pValue) {
		TrackName = pValue->TrackName;
		TrackAddress = pValue->TrackAddress; TrackLength = pValue->TrackLength; TrackLengthInTime = pValue->TrackLengthInTime;
		TrackType = pValue->TrackType;
	}
	// Test na audio track
	bool IsAudioTrack() {
		return (TrackType & 0x4) != 0x4;
	}
	// Ziskanie velkosti sektora
	unsigned int GetSectorSize() {
		return IsAudioTrack() ? RAW_SECTOR_SIZE : CD_SECTOR_SIZE;
	}
};
// ....................................................................................................................

// ....................................................................................................................
// Trieda ICDDriveReaded
// ....................................................................................................................
public ref class ICDDriveReaded : public IDisposable {
protected:
	HANDLE FHandle; // Handle zariadenia
	unsigned char *FReadBuffer; // Interny buffer pre citanie
	RAW_READ_INFO *FReadInfo; // Struktura pre citanie
	unsigned int FReadedSectors, FTotalSectorsToRead; // Pocitadla
	unsigned __int64 FStartReadSector;
	System::IO::FileStream ^FReadDataStream;
private:
	System::Collections::Generic::List<ITrackItem^> ^FTracks;
public:
	String^ DefaultTrackName; // Defaultny nazov stopy
	int ReadBufferLength; // Dlzka buffra pre citanie
public:
	property int TracksCount { int get(); };
	property ITrackItem^ default[int] { ITrackItem^ get(int); };
public:
	ICDDriveReaded(void); // Konstruktor
	~ICDDriveReaded(void); // Destruktor
public:
	void Close(void); // Uzatvorenie objektu
	int Open(wchar_t pDriveLetter); // Otvorenie objektu
public:
	int EjectCD(void); // Vysunutie CD
	int InsertCD(void); // Zasunutie CD
	int IsCDReady(void); // Test pripravenosti CD mechaniky
	int LockCD(void); // Uzamknutie zariadenia
	int UnlockCD(void); // Odomknutie zariadenia
public:
	int ReadTrackList(void); // Nacitanie zoznamu stop
public:
	int OpenAudioTrackForRead(int pIndex); // Otvorenie stopy pre citanie audia
	void CloseAudioTrackForRead(void); // Uzatvorenie stopy pre citanie audia
	int ReadAudioTrack(array<unsigned char> ^Result, int pStart, int pMaxLength); // Citanie z audio stopy
	int OpenDataTrackForRead(int pIndex); // Otvorenie stopy pre citanie dat
	void CloseDataTrackForRead(void); // Uzatvorenie stopy pre citanie dat
	int ReadDataTrack(array<unsigned char> ^Result, int pStart, int pMaxLength); // Citanie z datovej stopy
public:
	static unsigned __int64 TranslateAddressToSectors(unsigned char Addr[4]); // Prevod adresy na sektory
	static int GetTrackLengthInTime(unsigned char Addr1[4], unsigned char Addr2[4]); // Vypocet dlzky stopy v milisekundach
};
// ....................................................................................................................

}
